package org.pwwong.scalautils.animation

import scala.concurrent.SyncVar
import scala.concurrent.ops._
import java.util.{TimerTask,Timer}
import javax.swing.SwingUtilities

import org.pwwong.scalautils.signals.Signal
import org.pwwong.scalautils.signals.TimedSignal
import org.pwwong.scalautils.time._

class AnimatedSignal[T](
  val startValue:T,
  val endValue:T,
  val repeatBehavior:RepeatBehavior,
  val duration:Duration,
  _resolution:Duration,
  val evaluator:(Double,T,T)=>T,
  val interpolator:(Double)=>Double
) extends TimedSignal[T](_resolution,startValue){
  protected var startNano:Long = System.nanoTime
  protected var curRepeatCount:Int = 0
  protected var isForward:Boolean = true
  
  private def repeat(inv:Boolean) {
    curRepeatCount = curRepeatCount + 1
    startNano = System.nanoTime
    if(inv) isForward = !isForward    
  }
    
  private def evaluateNextValue(frac:Double):T = evaluator(interpolator(frac),startValue,endValue)
  
  override protected def onStart:T = {startNano = System.nanoTime; evaluateNextValue(if(isForward) 0.0 else 1.0)}
  override protected def onCycle:T = {
    val curFrac = if(isForward) Math.min(       (System.nanoTime.toDouble-startNano.toDouble) / duration.to_ns.toDouble, 1.0 )
                  else          Math.max( 1.0 - (System.nanoTime.toDouble-startNano.toDouble) / duration.to_ns.toDouble, 0.0 )
    // We're done
    if(curFrac == 1.0 || curFrac == 0.0)
      repeatBehavior match {
        case NumberedRepeats(numReps,inv) => if(curRepeatCount+1 >= numReps) stop 
                                             else repeat(inv) 
        case RepeatIndefinitely(inv) => repeat(inv)
      }
    
    evaluateNextValue(curFrac)
  }
  
}
